#include "iec10X_protocol.h"
#include "iec10X_frame.h"
#include "log.h"
#include <pthread.h>
#include <stdlib.h>

struct IEC10X_Protocol
{
    struct 
    {
        int (*read)(void* p, void* buf, int bytes); /*最多读bytes个字节的数据。返回值：<0:错误码；[0,bytes]:正确 */
        int (*write)(void* p, const void* buf, int bytes); /*最多写bytes个字节的数据。返回值：<0:错误码；[0,bytes]:正确*/
        int (*reset)(void* p); /*发生错误后用来重置*/
        void* priv; /*p==priv*/
    } io;
    struct 
    {
        int(*is_interrupted)(void* p); /*检测是否需要中断内部循环。返回值：1：中断；0：不中断*/
        void* priv;
    } interrupter;

    unsigned short remote_id;
    unsigned short my_id; //本机序号
};

static int IsInterrupted(IEC10X_Protocol_T* self)
{
    return self->interrupter.is_interrupted(self->interrupter.priv);
}

static int ResetUntil(IEC10X_Protocol_T* self)
{
    int ret = -1;
        
    while (!IsInterrupted(self) && ret < 0)
    {
        ret = self->io.reset(self->io.priv);
    }

    return ret;
}

static int ReadUntil(IEC10X_Protocol_T* self, void* buf, int bytes)
{
    int count = 0;
    int ret;

    while (!IsInterrupted(self) && count < bytes)
    {
        ret = self->io.read(self->io.priv, (char*)buf+count, bytes-count);
        if(ret < 0)
        {
            ResetUntil(self);
            break;
        }
        count += ret;
    }
    
    return count;
}

static int WriteUntil(IEC10X_Protocol_T* self, const void* buf, int bytes)
{
    int count = 0;
    int ret;

    while (!IsInterrupted(self) && count < bytes)
    {
        ret = self->io.write(self->io.priv, (const char*)buf+count, bytes-count);
        if(ret < 0)
        {
            ResetUntil(self);
            break;
        }
        count += ret;        
    }
    
    return count;
}

static int IEC10X_Protocol_GenID(IEC10X_Protocol_T* self)
{
    self->my_id++;
    return self->my_id;
}
static void IEC10X_Protocol_ResetID(IEC10X_Protocol_T* self)
{
    self->remote_id = self->my_id = 0;
}

//填充帧缺失的公共信息。
static void IEC10X_Protocol_MakeIFrame(IEC10X_Protocol_T* self, IEC10X_Frame_T* frame)
{
    IEC10X_Frame_SetID(frame, self->remote_id, IEC10X_Protocol_GenID(self));
    IEC10X_Frame_SetAddr(frame, 1); //临时用1，后续优化
}

static void IEC10X_Protocol_DoResp(IEC10X_Protocol_T* self, const IEC10X_Frame_T* frame)
{
    int ret;

    LogHex("send frame:", frame->data, IEC10X_Frame_Bytes(frame));
    ret = WriteUntil(self, frame->data, IEC10X_Frame_Bytes(frame));
    if(ret != IEC10X_Frame_Bytes(frame))
    {
        LogWarn("write frame fail. ret=%d", ret);
        LogHex("drop frame:", frame->data, IEC10X_Frame_Bytes(frame));
    }
}

static void IEC10X_Protocol_Resp64(IEC10X_Protocol_T* self, IEC10X_Frame_T* frame)
{
    //总召唤确认帧 -- 这个帧测试软件报 帧长度错误。不知道为什么
    IEC10X_Frame_Clear(frame);
    IEC10X_Frame_SetCmd(frame, 0x64);
    IEC10X_Frame_SetReason(frame, IEC10X_REASON_ACTIVATION_CONFIRM);
    IEC10X_Frame_AddObject(frame, 0x00, 0x14, IEC10X_QDS_NONE); //总召唤规定对象地址为0，对象为0x14.无时标，无品质。
    IEC10X_Protocol_MakeIFrame(self, frame);
    IEC10X_Protocol_DoResp(self, frame);
    //多个数据帧待补充
    //总召唤终止帧
    IEC10X_Frame_Clear(frame);
    IEC10X_Frame_SetCmd(frame, 0x64);
    IEC10X_Frame_SetReason(frame, IEC10X_REASON_ACTIVATION_TERMINATE);
    IEC10X_Frame_AddObject(frame, 0x00, 0x14, IEC10X_QDS_NONE); //总召唤规定对象地址为0，对象为0x14，无时标，无品质。
    IEC10X_Protocol_MakeIFrame(self, frame);
    IEC10X_Protocol_DoResp(self, frame);
}

static void IEC10X_Protocol_Resp67(IEC10X_Protocol_T* self, IEC10X_Frame_T* frame)
{
    long long ms = IEC10X_Frame_Time(frame);
    LogDebug("frame time ms=%lld", ms);
}

static void IEC10X_Protocol_HandleReq(IEC10X_Protocol_T* self, IEC10X_Frame_T* frame)
{
    LogHex("recv frame:", frame->data, IEC10X_Frame_Bytes(frame));
    switch(IEC10X_Frame_Fmt(frame))
    {
        case IEC10X_Frame_FMT_U: //控制帧
        {
            if(IEC10X_Frame_IsEqual(frame, IEC10X_FRAME_STARTDT())) //启动帧
            {
                IEC10X_Protocol_ResetID(self); //重置序号
                IEC10X_Protocol_DoResp(self, IEC10X_FRAME_STARTDT_ACK());
                return;
            }
            if(IEC10X_Frame_IsEqual(frame, IEC10X_FRAME_TESTFR())) //测试帧
            {
                IEC10X_Protocol_DoResp(self, IEC10X_FRAME_TESTFR_ACK());
                return;
            }

        } break;
        case IEC10X_Frame_FMT_I: //信息帧
        {
            if(IEC10X_Frame_SendID(frame) != self->remote_id) break; //错误帧
            self->remote_id++; 
            switch(IEC10X_Frame_Cmd(frame))
            {
                case 0x64: /*总召唤*/ {IEC10X_Protocol_Resp64(self, frame); return;}
                case 0x67: /*时钟同步*/{IEC10X_Protocol_Resp67(self, frame); return;}
            }
        } break;
        default: break;
        
    }

    
    LogHex("unknown frame:", frame->data, IEC10X_Frame_Bytes(frame));
}

void IEC10X_Protocol_SetIO(IEC10X_Protocol_T* self, 
    int (*read)(void* p, char* buf, int len), /*最多读len个字节的数据。返回值：<0:错误码；[0,len]:正确 */
    int (*write)(void* p, const char* buf, int len), /*最多写len个字节的数据。返回值：<0:错误码；[0,len]:正确*/
    int (*reset)(void* p), /*发生错误后用来重置*/
    void* priv /*p==priv*/
)
{
    self->io.read = read;
    self->io.write = write;
    self->io.reset = reset;
    self->io.priv = priv;
}

void IEC10X_Protocol_SetInterrupter(IEC10X_Protocol_T* self,
    int(*is_interrupted)(void* p), /*检测是否需要中断内部循环。返回值：1：中断；0：不中断*/
    void* priv
)
{
    self->interrupter.is_interrupted = is_interrupted;
    self->interrupter.priv = priv;
}

IEC10X_Protocol_T* IEC10X_Protocol_Create()
{
    IEC10X_Protocol_T* self = (IEC10X_Protocol_T *)calloc(1, sizeof(*self));
    return self;
}

void IEC10X_Protocol_Destroy(IEC10X_Protocol_T* self)
{
    free(self);
}

void IEC10X_Protocol_Run(IEC10X_Protocol_T* self)
{
    IEC10X_Frame_T frame;
    unsigned char* dp;

    while(!IsInterrupted(self))
    {
        IEC10X_Frame_Clear(&frame);
        dp = frame.data;
        
        //帧头
        if(ReadUntil(self, dp, 1) != 1)  continue;
        if(IEC10X_Frame_Length(&frame) != 0) //此时应为0
        {
            LogWarn("frame header invalid");
            continue;
        }
        dp++;

        //帧长度
         if(ReadUntil(self, dp, 1) != 1) continue;
        if(IEC10X_Frame_Length(&frame) < 4 || IEC10X_Frame_Length(&frame) > 253) //协议规定[4,253]
        {
            LogWarn("frame length invalid");
            continue;
        }
        dp++;

        //帧内容 
        if(ReadUntil(self, dp, IEC10X_Frame_Length(&frame)) != IEC10X_Frame_Length(&frame))  continue;

        //协议不支持内容校验

        //处理帧
        IEC10X_Protocol_HandleReq(self, &frame);
    }
}
